<?php
// vim: set ts=4 sw=4 sts=4 et:

/**
 * LiteCommerce
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to licensing@litecommerce.com so we can send you a copy immediately.
 *
 * PHP version 5.3.0
 *
 * @category  LiteCommerce
 * @author    Creative Development LLC <info@cdev.ru>
 * @copyright Copyright (c) 2011 Creative Development LLC <info@cdev.ru>. All rights reserved
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
 * @link      http://www.litecommerce.com/
 * @see       ____file_see____
 * @since     1.0.0
 */

namespace XLite\Model;

/**
 * Cart
 *
 * @see   ____class_see____
 * @since 1.0.0
 *
 * @Entity (repositoryClass="\XLite\Model\Repo\Cart")
 * @HasLifecycleCallbacks
 */
class Cart extends \XLite\Model\Order
{
    /**
     * Array of instances for all derived classes
     *
     * @var   array
     * @see   ____var_see____
     * @since 1.0.0
     */
    protected static $instances = array();

    /**
     * Method to access a singleton
     *
     * @return \XLite\Model\Cart
     * @see    ____func_see____
     * @since  1.0.0
     */
    public static function getInstance()
    {
        $className = get_called_class();

        // Create new instance of the object (if it is not already created)
        if (!isset(static::$instances[$className])) {
            $orderId = \XLite\Core\Session::getInstance()->order_id;

            if ($orderId) {
                $cart = \XLite\Core\Database::getRepo('XLite\Model\Cart')->find($orderId);

                if ($cart && self::STATUS_TEMPORARY != $cart->getStatus()) {
                    \XLite\Core\Session::getInstance()->order_id = 0;

                    $cart = null;
                }
            }

            if (!isset($cart)) {
                $cart = new $className();
                $cart->setStatus(self::STATUS_TEMPORARY);

                \XLite\Core\Database::getEM()->persist($cart);

                $cart->setCurrency(\XLite::getInstance()->getCurrency());
            }

            static::$instances[$className] = $cart;

            $auth = \XLite\Core\Auth::getInstance();

            if ($auth->isLogged()) {
                if (
                    !$cart->getProfile()
                    || $auth->getProfile()->getProfileId() != $cart->getProfile()->getProfileId()
                ) {
                    $cart->setProfile($auth->getProfile());
                    $cart->setOrigProfile($auth->getProfile());
                    $cart->calculate();
                }

            } elseif ($cart->getProfile() && $cart->getProfile()->getProfileId()) {

                $cart->setProfile(null);
                $cart->calculate();
            }

            \XLite\Core\Database::getEM()->flush();

            \XLite\Core\Session::getInstance()->order_id = $cart->getOrderId();

        }

        return static::$instances[$className];
    }

    /**
     * Set object instance
     *
     * @param \XLite\Model\Cart $cart Cart
     *
     * @return void
     * @see    ____func_see____
     * @since  1.0.0
     */
    public static function setObject(\XLite\Model\Cart $cart)
    {
        $className = get_called_class();
        static::$instances[$className] = $cart;
        \XLite\Core\Session::getInstance()->order_id = $cart->getOrderId();
    }

    /**
     * Prepare order before save data operation
     *
     * @return void
     * @see    ____func_see____
     * @since  1.0.0
     * @PrePersist
     * @PreUpdate
     */
    public function prepareBeforeSave()
    {
        parent::prepareBeforeSave();

        $this->setDate(time());
    }

    /**
     * Clear cart
     *
     * @return void
     * @see    ____func_see____
     * @since  1.0.0
     */
    public function clear()
    {
        foreach ($this->getItems() as $item) {
            \XLite\Core\Database::getEM()->remove($item);
        }

        $this->setCurrency(\XLite::getInstance()->getCurrency());

        $this->getItems()->clear();

        \XLite\Core\Database::getEM()->persist($this);
        \XLite\Core\Database::getEM()->flush();
    }


    /**
     * Checks whether a product is in the cart
     *
     * @param integer $productId ID of the product to look for
     *
     * @return boolean
     * @see    ____func_see____
     * @since  1.0.0
     */
    public function isProductAdded($productId)
    {
        $result = false;

        foreach ($this->getItems() as $item) {
            $product = $item->getProduct();

            if ($product && $product->getProductId() == $productId) {
                $result = true;
                break;
            }
        }

        return $result;
    }


    /**
     * Prepare order before remove operation
     *
     * @return void
     * @see    ____func_see____
     * @since  1.0.0
     * @PreRemove
     */
    public function prepareBeforeRemove()
    {
        parent::prepareBeforeRemove();

        unset(\XLite\Core\Session::getInstance()->order_id);
    }

    /**
     * Mark cart as order
     *
     * @return void
     * @see    ____func_see____
     * @since  1.0.0
     */
    public function markAsOrder()
    {
        $this->getRepository()->markAsOrder($this->getOrderId());
    }

    /**
     * If we can proceed with checkout with current cart
     *
     * @return boolean
     * @see    ____func_see____
     * @since  1.0.0
     */
    public function checkCart()
    {
        return
            !$this->isEmpty()
            && !((bool) $this->getItemsWithWrongAmounts())
            && !$this->isMinOrderAmountError()
            && !$this->isMaxOrderAmountError();
    }

    /**
     * Get order_id
     *
     * @return integer $orderId
     */
    public function getOrderId()
    {
        return $this->order_id;
    }

    /**
     * Set shipping_id
     *
     * @param integer $shippingId
     */
    public function setShippingId($shippingId)
    {
        $this->shipping_id = $shippingId;
    }

    /**
     * Get shipping_id
     *
     * @return integer $shippingId
     */
    public function getShippingId()
    {
        return $this->shipping_id;
    }

    /**
     * Set shipping_method_name
     *
     * @param string $shippingMethodName
     */
    public function setShippingMethodName($shippingMethodName)
    {
        $this->shipping_method_name = $shippingMethodName;
    }

    /**
     * Get shipping_method_name
     *
     * @return string $shippingMethodName
     */
    public function getShippingMethodName()
    {
        return $this->shipping_method_name;
    }

    /**
     * Set tracking
     *
     * @param string $tracking
     */
    public function setTracking($tracking)
    {
        $this->tracking = $tracking;
    }

    /**
     * Get tracking
     *
     * @return string $tracking
     */
    public function getTracking()
    {
        return $this->tracking;
    }

    /**
     * Set date
     *
     * @param integer $date
     */
    public function setDate($date)
    {
        $this->date = $date;
    }

    /**
     * Get date
     *
     * @return integer $date
     */
    public function getDate()
    {
        return $this->date;
    }

    /**
     * Get status
     *
     * @return fixedstring $status
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * Set notes
     *
     * @param text $notes
     */
    public function setNotes($notes)
    {
        $this->notes = $notes;
    }

    /**
     * Get notes
     *
     * @return text $notes
     */
    public function getNotes()
    {
        return $this->notes;
    }

    /**
     * Set total
     *
     * @param decimal $total
     */
    public function setTotal($total)
    {
        $this->total = $total;
    }

    /**
     * Get total
     *
     * @return decimal $total
     */
    public function getTotal()
    {
        return $this->total;
    }

    /**
     * Set subtotal
     *
     * @param decimal $subtotal
     */
    public function setSubtotal($subtotal)
    {
        $this->subtotal = $subtotal;
    }

    /**
     * Get subtotal
     *
     * @return decimal $subtotal
     */
    public function getSubtotal()
    {
        return $this->subtotal;
    }

    /**
     * Get profile
     *
     * @return XLite\Model\Profile $profile
     */
    public function getProfile()
    {
        return $this->profile;
    }

    /**
     * Add details
     *
     * @param XLite\Model\OrderDetail $details
     */
    public function addDetails(\XLite\Model\OrderDetail $details)
    {
        $this->details[] = $details;
    }

    /**
     * Get details
     *
     * @return Doctrine\Common\Collections\Collection $details
     */
    public function getDetails()
    {
        return $this->details;
    }

    /**
     * Add items
     *
     * @param XLite\Model\OrderItem $items
     */
    public function addItems(\XLite\Model\OrderItem $items)
    {
        $this->items[] = $items;
    }

    /**
     * Get items
     *
     * @return Doctrine\Common\Collections\Collection $items
     */
    public function getItems()
    {
        return $this->items;
    }

    /**
     * Add surcharges
     *
     * @param XLite\Model\Order\Surcharge $surcharges
     */
    public function addSurcharges(\XLite\Model\Order\Surcharge $surcharges)
    {
        $this->surcharges[] = $surcharges;
    }

    /**
     * Get surcharges
     *
     * @return Doctrine\Common\Collections\Collection $surcharges
     */
    public function getSurcharges()
    {
        return $this->surcharges;
    }

    /**
     * Add payment_transactions
     *
     * @param XLite\Model\Payment\Transaction $paymentTransactions
     */
    public function addPaymentTransactions(\XLite\Model\Payment\Transaction $paymentTransactions)
    {
        $this->payment_transactions[] = $paymentTransactions;
    }

    /**
     * Get payment_transactions
     *
     * @return Doctrine\Common\Collections\Collection $paymentTransactions
     */
    public function getPaymentTransactions()
    {
        return $this->payment_transactions;
    }

    /**
     * Set currency
     *
     * @param XLite\Model\Currency $currency
     */
    public function setCurrency(\XLite\Model\Currency $currency)
    {
        $this->currency = $currency;
    }

    /**
     * Get currency
     *
     * @return XLite\Model\Currency $currency
     */
    public function getCurrency()
    {
        return $this->currency;
    }
}